using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;

namespace TheBox
{
    /// <summary>
    /// This is the main type for your game
    /// </summary>
    public class Game1 : Microsoft.Xna.Framework.Game
    {
        GraphicsDeviceManager graphics;
        SpriteBatch spriteBatch;
        Random Rand = new Random();
        enum GameStates { TitleScreen, Playing, GameOver };
        GameStates gameState = GameStates.TitleScreen;
        private Box[] boxes;
        private List<Player> players;
        private float currentSleepBeforeTurn = 0.0f;
        private float currentSleepBeforeParticle = 0.0f;

        #region textures and fonts
        private Texture2D squareTexture;
        private Texture2D particleTexture;
        private Texture2D playerTexture;
        private Texture2D heartTexture;
        private Texture2D fireTexture;

        private SpriteFont font;

        #endregion
        #region magicNumbers
        private static float sleepBeforeNextKey = 0.2f;
        private static int screenWitdh   = 800;
        private static int screenHeight  = 600;
        private static int boxY  = (int)(80 + (float)Box.Origin.Y);
        private static int firstBoxX = (int)(80 + (float)Box.Origin.X);
        private static int secondBoxX = firstBoxX + Box.BoxWidth + 140;
        private static float sleepBeforeTurn = 8.0f;
        private static float sleepBeforeParticle = 1.0f;
        private Texture2D titleScreen;
        private Texture2D gameOver;

        #endregion

        public Game1()
        {
            graphics = new GraphicsDeviceManager(this);
            Content.RootDirectory = "Content";
        }

        private void restartGame()
        {
            players = new List<Player>();
            for (int i = 0; i < 2; i++)
                boxes[i] = new Box(Rand);
            
            boxes[0].Position.X = firstBoxX;
            boxes[1].Position.X = secondBoxX;

            boxes[0].Player = new Player(font, boxes[0], playerTexture, 100, heartTexture,
                Keys.W, Keys.S, Keys.A, Keys.D, Keys.LeftControl);
            boxes[1].Player = new Player(font, boxes[1], playerTexture, 100 + Box.BoxWidth + 140, heartTexture,
                Keys.Up,Keys.Down,Keys.Left,Keys.Right,Keys.RightControl);
            for (int i = 0; i < 2; i++)
            {
                boxes[i].Position.Y = boxY;
                boxes[i].Texture = squareTexture;
                boxes[i].Rect = new Rectangle((int)boxes[i].Position.X,
                                              (int)boxes[i].Position.Y,
                                               Box.BoxWidth,
                                               Box.BoxHeight);
                players.Add(boxes[i].Player);
            }
            currentSleepBeforeTurn = sleepBeforeTurn;
            gameState = GameStates.Playing;

        }

        /// <summary>
        /// Allows the game to perform any initialization it needs to before starting to run.
        /// This is where it can query for any required services and load any non-graphic
        /// related content.  Calling base.Initialize will enumerate through any components
        /// and initialize them as well.
        /// </summary>
        protected override void Initialize()
        {
            graphics.PreferredBackBufferWidth = screenWitdh;
            graphics.PreferredBackBufferHeight = screenHeight;
            graphics.ApplyChanges();
            
            boxes = new Box[2];

            base.Initialize();
        }

        /// <summary>
        /// LoadContent will be called once per game and is the place to load
        /// all of your content.
        /// </summary>
        protected override void LoadContent()
        {
            // Create a new SpriteBatch, which can be used to draw textures.
            spriteBatch = new SpriteBatch(GraphicsDevice);
            titleScreen = Content.Load<Texture2D>(@"Textures\TitleScreen");
            gameOver = Content.Load<Texture2D>(@"Textures\GameOver");
            squareTexture = Content.Load<Texture2D>(@"Textures\Square");
            particleTexture = Content.Load<Texture2D>(@"Textures\particle");
            playerTexture = Content.Load<Texture2D>(@"Textures\player");
            heartTexture = Content.Load<Texture2D>(@"Textures\heart");
            fireTexture = Content.Load<Texture2D>(@"Textures\fire");
            font = Content.Load<SpriteFont>(@"myFont"); 
        }

        /// <summary>
        /// UnloadContent will be called once per game and is the place to unload
        /// all content.
        /// </summary>
        protected override void UnloadContent()
        {
            // TODO: Unload any non ContentManager content here
        }

        /// <summary>
        /// Allows the game to run logic such as updating the world,
        /// checking for collisions, gathering input, and playing audio.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        protected override void Update(GameTime gameTime)
        {
            // Allows the game to exit
            if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
                this.Exit();



            switch (gameState)
            {
                case GameStates.TitleScreen:
                case GameStates.GameOver:
                    if (Keyboard.GetState().IsKeyDown(Keys.Space))
                    {
                        restartGame();
                        return;
                    }
                    break;
                case GameStates.Playing:
                    foreach (Player curPlayer in players)
                    {
                        if (curPlayer.IsDead())
                        {
                            gameState = GameStates.GameOver;
                            return;
                        }
                        Vector2 speed = new Vector2(0, 0);
                        if (Keyboard.GetState().IsKeyDown(curPlayer.UpKey))
                            speed += new Vector2(0, -1);
                        if (Keyboard.GetState().IsKeyDown(curPlayer.DownKey))
                            speed += new Vector2(0, 1);
                        speed *= (float)gameTime.ElapsedGameTime.TotalSeconds;
                        curPlayer.addSpeed(speed);

                        if (Keyboard.GetState().IsKeyDown(curPlayer.LeftKey))
                            curPlayer.Rotation -= Player.RotationSpeed * (float)gameTime.ElapsedGameTime.TotalSeconds;
                        if (Keyboard.GetState().IsKeyDown(curPlayer.RightKey))
                            curPlayer.Rotation += Player.RotationSpeed * (float)gameTime.ElapsedGameTime.TotalSeconds;

                        curPlayer.CurrentSleepBeforeNextShot -= (float)gameTime.ElapsedGameTime.TotalSeconds;
                        if (curPlayer.CurrentSleepBeforeNextShot <= 0)
                        {
                            if (Keyboard.GetState().IsKeyDown(curPlayer.FireKey))
                            {
                                curPlayer.BaseBox.Shots.Add(new Fire(curPlayer.BaseBox, fireTexture, curPlayer));
                                curPlayer.CurrentSleepBeforeNextShot = sleepBeforeNextKey;
                            }
                        }

                    }

                    currentSleepBeforeTurn -= (float)gameTime.ElapsedGameTime.TotalSeconds;
                    currentSleepBeforeParticle -= (float)gameTime.ElapsedGameTime.TotalSeconds;


                    foreach(Box curBox in boxes)
                    {
                        if (currentSleepBeforeTurn <= 0)
                        {
                            if(Rand.Next(0,2) == 0)
                                curBox.StartRotation(MathHelper.Pi / 2, false);
                            else
                                curBox.StartRotation(MathHelper.Pi / 2, true);
                        }
                        if (currentSleepBeforeParticle <= 0)
                            curBox.Particles.Add(new Particle(curBox, particleTexture, Rand));
                        curBox.update(gameTime);
                    }
                    if (currentSleepBeforeTurn <= 0)
                        currentSleepBeforeTurn += sleepBeforeTurn;
                    if (currentSleepBeforeParticle <= 0)
                        currentSleepBeforeParticle += sleepBeforeParticle;
                    break;
            }

            base.Update(gameTime);
        }

        /// <summary>
        /// This is called when the game should draw itself.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        protected override void Draw(GameTime gameTime)
        {
            GraphicsDevice.Clear(Color.Black);


            spriteBatch.Begin();

            switch (gameState)
            {
                case GameStates.GameOver:
                    spriteBatch.Draw(gameOver,
                        new Rectangle(0, 0,
                            this.Window.ClientBounds.Width,
                            this.Window.ClientBounds.Height),
                        Color.White);
                    break;
                case GameStates.TitleScreen:
                    spriteBatch.Draw(titleScreen,
                        new Rectangle(0, 0,
                            this.Window.ClientBounds.Width,
                            this.Window.ClientBounds.Height),
                        Color.White);
                    break;
                case GameStates.Playing:
                    foreach (Box curBox in boxes)
                    {
                        spriteBatch.Draw(curBox.Texture,
                            curBox.Position,
                            null,
                            Color.White,
                            curBox.Rotation,
                            Box.Origin,
                            1.0f,
                            SpriteEffects.None,
                            0f);


                        foreach (Fire curFire in curBox.Shots)
                            spriteBatch.Draw(curFire.Texture,curFire.Rect,Color.White);

                        foreach (Particle p in curBox.Particles)
                            spriteBatch.Draw(p.Texture,p.Rect,Color.White);

                        spriteBatch.Draw(curBox.Player.Texture,
                                curBox.Player.Rect,
                                null,
                                Color.White,
                                curBox.Player.Rotation,
                                Player.Origin,
                                SpriteEffects.None,
                                0f);
                        curBox.Player.DrawInfo(spriteBatch);
                    }
                    break;
            }
            spriteBatch.End();

            base.Draw(gameTime);
        }
    }
}
